package com.heima.comment.service.impl;

import com.alibaba.fastjson.JSON;
import com.heima.api.UserFeignClient;
import com.heima.comment.dtos.CommentRepayDto;
import com.heima.comment.dtos.CommentRepayLikeDto;
import com.heima.comment.dtos.CommentRepayListDto;
import com.heima.comment.pojos.ApComment;
import com.heima.comment.pojos.ApCommentLike;
import com.heima.comment.service.CommentRepayService;
import com.heima.comment.vo.ApCommentVo;
import com.heima.common.aliyun.GreenTextScan;
import com.heima.model.common.dtos.ResponseResult;
import com.heima.model.common.enums.AppHttpCodeEnum;
import com.heima.model.user.pojos.ApUser;
import com.heima.utils.thread.ApThreadLocalUtil;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Sort;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.data.mongodb.core.query.Update;
import org.springframework.data.mongodb.core.query.UpdateDefinition;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;

import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

/**
 * @author DiXiaoNie
 * @since 2023/1/5 19:01
 */
@Service
public class CommentRepayServiceImpl implements CommentRepayService {
    @Autowired
    private StringRedisTemplate redisTemplate;

    @Autowired
    private MongoTemplate mongoTemplate;

    @Autowired
    private UserFeignClient userFeignClient;

    /**
     * 发送评论回复
     *
     * @param dto dto
     * @return {@link ResponseResult }
     * @author DiXiaoNie
     * @date 2023/01/05
     */
    @Override
    public ResponseResult save(CommentRepayDto dto) {
        //1.参数校验
        if (dto == null || dto.getCommentId() == null) {
            return ResponseResult.errorResult(AppHttpCodeEnum.PARAM_INVALID);
        }
        if (StringUtils.isBlank(dto.getContent())) {
            return ResponseResult.errorResult(5001, "评论不可为空");
        } else if (dto.getContent().length() > 140) {
            return ResponseResult.errorResult(AppHttpCodeEnum.PARAM_INVALID.getCode(), "评论内容不可超过140字");
        }
        //2.获取用户id
        ApUser apUser = ApThreadLocalUtil.getApUserThreadLocal();
        if (apUser == null) {
            return ResponseResult.errorResult(AppHttpCodeEnum.DATA_NOT_EXIST);
        }
        if (apUser.getId() == 0) {
            return ResponseResult.errorResult(5001, "游客不可评论");
        }
        //3.先查询redis，获取用户信息，如果不存在，则远程调用user服务，并添加数据到redis中
        String key = "LOGIN_USER_" + apUser.getId();
        String apUserStr = redisTemplate.opsForValue().get(key);
        if (StringUtils.isBlank(apUserStr)) {
            //redis中不存在
            ResponseResult<ApUser> responseResult = this.userFeignClient.findApUserById(apUser.getId());
            if (responseResult.getCode() == 200) {
                apUser = responseResult.getData();
                //添加数据到redis中
                this.redisTemplate.opsForValue().set(key, JSON.toJSONString(apUser), 2, TimeUnit.HOURS);
            }
        } else {
            //redis中存在
            apUser = JSON.parseObject(apUserStr, ApUser.class);
        }

        // TODO: 2023/1/5  对文本内容进行安全过滤，调用内容安全审核接口
/*        Boolean flag = scanTextFilter(dto.getContent());
        if (!flag) {
            return ResponseResult.errorResult(501, "评论内容不符合规定");
        }*/
        //4.保存数据到mongo中
        ApComment apComment = new ApComment();
        apComment.setUserId(apUser.getId());
        apComment.setNickName(apUser.getName());
        apComment.setImage(apUser.getImage());
        apComment.setTargetId(dto.getCommentId());
        apComment.setContent(dto.getContent());
        apComment.setLikes(0);
        apComment.setReply(0);
        apComment.setCreatedTime(new Date());
        apComment.setUpdatedTime(new Date());
        this.mongoTemplate.insert(apComment);

        return ResponseResult.okResult("发表评论成功");
    }

    /**
     * 回显评论回复
     *
     * @param dto dto
     * @return {@link ResponseResult }
     * @author DiXiaoNie
     * @date 2023/01/05
     */
    @Override
    public ResponseResult load(CommentRepayListDto dto) {
        //1.参数校验
        if (dto == null || dto.getCommentId() == null) {
            return ResponseResult.errorResult(AppHttpCodeEnum.PARAM_INVALID);
        }
        if (dto.getSize() == null || dto.getSize() != 10) {
            dto.setSize(10);
        }
        //2.根据文章Id查询mongo，降序展示和分页查询
        List<ApComment> apCommentList = this.mongoTemplate.find(Query.query(
                Criteria.where("targetId").is(dto.getCommentId().toString()).and("createdTime").lt(dto.getMinDate())
                ).with(
                Sort.by(Sort.Direction.DESC, "updatedTime")
                ).limit(dto.getSize())
                , ApComment.class);
        //3.如果是游客登录
        ApUser apUser = ApThreadLocalUtil.getApUserThreadLocal();
        if (apUser != null && apUser.getId() == 0) {
            return ResponseResult.okResult(apCommentList);
        }
        //4.如果是用户登录  而且当前用户点赞过评论，我们要让点赞按钮高亮
        String key = "COMMENT_REPAY_LIKE_" + apUser.getId();
        //根据key获取所有的redis的value
        Set<String> memberIdSet = this.redisTemplate.opsForSet().members(key);
        //遍历apCommentList 然后比较当前list中的id是否存在与memberId中，如果存在，则认为点赞过，反之没有点赞过
        List<ApCommentVo> comments = apCommentList.stream().map(apComment -> {
            ApCommentVo apCommentVo = new ApCommentVo();
            BeanUtils.copyProperties(apComment, apCommentVo);
            //1.获取每个list中的评论id
            String commentId = apComment.getId();
            //2.看当前id是否存在于set集合中
            if (memberIdSet.contains(commentId)) {
                apCommentVo.setOperation((short) 0);
            }
            return apCommentVo;
        }).collect(Collectors.toList());
        return ResponseResult.okResult(comments);
    }

    /**
     * 回复评论点赞
     *
     * @param dto dto
     * @return {@link ResponseResult }
     * @author DiXiaoNie
     * @date 2023/01/05
     */
    @Override
    public ResponseResult like(CommentRepayLikeDto dto) {
        //1.参数校验
        if (dto == null || StringUtils.isBlank(dto.getCommentRepayId()) || dto.getOperation() == null) {
            return ResponseResult.errorResult(AppHttpCodeEnum.PARAM_INVALID);
        }
        //2.获取用户Id
        ApUser apUser = ApThreadLocalUtil.getApUserThreadLocal();
        if (apUser == null) {
            return ResponseResult.errorResult(AppHttpCodeEnum.NEED_LOGIN);
        } else if (apUser.getId() == 0) {
            return ResponseResult.errorResult(501, "游客不可点赞");
        }

        //2.5 去查询mongo中评论集合
        ApComment apComment = this.mongoTemplate.findById(dto.getCommentRepayId(), ApComment.class);
        if (apComment == null) {
            return ResponseResult.errorResult(AppHttpCodeEnum.DATA_NOT_EXIST);
        }
        //3.查询redis 是否点赞过
        String key = "COMMENT_REPAY_LIKE_" + apUser.getId();
        //判断当前redis中是否是当前成员内容
        Boolean memberFlag = this.redisTemplate.opsForSet().isMember(key, dto.getCommentRepayId());

        //4.1 如果点赞过，并且正在执行的是点赞操作，operation = 0 则返回
        if (memberFlag && dto.getOperation() == 0) {
            return ResponseResult.errorResult(5003, "当前用户已点赞过该数据");
        }
        //4.2 如果没点赞过，并且正在执行的是取消点赞操作，operation = 1 则返回
        if (!memberFlag && dto.getOperation() == 1) {
            return ResponseResult.errorResult(5003, "当前用户还没有点赞过此评论");
        }
        //4.3 如果点赞过，并且正在执行的是取消点赞操作，operation = 1 删除redis和mongo
        if (memberFlag && dto.getOperation() == 1) {
            this.redisTemplate.opsForSet().remove(key, dto.getCommentRepayId());

            this.mongoTemplate.remove(Query.query(
                    Criteria.where("userId").is(apUser.getId()).and("targetId").is(dto.getCommentRepayId())
            ), ApCommentLike.class);
            //修改评论集合
            //apComment.setLikes(apComment.getLikes() > 0 ? apComment.getLikes() - 1 : 0);
            //this.mongoTemplate.save(apComment);

            Query query = Query.query(
                    Criteria.where("id").is(dto.getCommentRepayId()).and("likes").gt(0)
            );
            UpdateDefinition update = new Update().inc("likes", -1);
            mongoTemplate.updateFirst(query, update, ApComment.class);

        }
        //4.4 如果没有点赞过，并且正在执行的是点赞操作，operation = 0 保存数据到redis和mongo中
        if (!memberFlag && dto.getOperation() == 0) {
            this.redisTemplate.opsForSet().add(key, dto.getCommentRepayId());

            ApCommentLike apCommentLike = new ApCommentLike();
            apCommentLike.setUserId(apUser.getId());
            apCommentLike.setTargetId(dto.getCommentRepayId());
            apCommentLike.setCreatedTime(new Date());
            this.mongoTemplate.insert(apCommentLike);

            //修改评论集合+1
            //apComment.setLikes(apComment.getLikes() + 1);
            //this.mongoTemplate.save(apComment);

            Query query = Query.query(
                    Criteria.where("id").is(dto.getCommentRepayId())
            );
            UpdateDefinition update = new Update().inc("likes", 1);
            mongoTemplate.updateFirst(query, update, ApComment.class);
        }

        apComment = this.mongoTemplate.findById(dto.getCommentRepayId(), ApComment.class);
        Map map = new HashMap();
        map.put("likes", apComment.getLikes());

        return ResponseResult.okResult(map);
    }


    /**
     * 对评论信息进行安全审核
     *
     * @param content
     */
    @Autowired
    private GreenTextScan greenTextScan;

    private Boolean scanTextFilter(String content) {
        Boolean flag = true;
        try {
            Map map = greenTextScan.greeTextScan(content);
            //表示违规
            if (map != null && !map.get("suggestion").equals("pass")) {
                flag = false;
            }
        } catch (Exception e) {
            e.printStackTrace();
            flag = false;
        }
        return flag;
    }
}
